home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 18 / AMIGAplus Sonderheft 18 (1999)(ICP)(DE)[!].iso / PD / Anwendungen / FS1541-13 / volume.c < prev    next >
C/C++ Source or Header  |  1999-01-03  |  14KB  |  656 lines

  1.  
  2. /*
  3.  * FS1541 - volume, BAM and lock handling
  4.  *
  5.  * Copyright (C) 1996 - 1998 Michael Krause
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include <stdio.h> /* contains decl of sprintf, but will be linked from amiga.lib! */
  23. #include <string.h>
  24.  
  25. #include <exec/types.h>
  26. #include <exec/execbase.h>
  27. #include <exec/memory.h>
  28. #include <dos/dosextens.h>
  29. #include <dos/filehandler.h>
  30. #include <devices/trackdisk.h>
  31. #include <devices/timer.h>
  32.  
  33. #include <proto/exec.h>
  34. #include <proto/dos.h>
  35. #include <proto/alib.h>
  36. #include <proto/utility.h>
  37.  
  38. #include "main.h"
  39. #include "volume.h"
  40. #include "disk.h"
  41. #include "packet.h"
  42. #include "support.h"
  43.  
  44. BYTE diskchgintbit = -1;
  45. struct VolumeNode *curvolumenode = NULL;
  46. struct DosList *curdoslist = NULL;
  47.  
  48. int disk_inserted = FALSE;
  49.  
  50. struct BAM *bam;
  51. struct DirEntry directory[144];
  52. int dirsize;
  53.  
  54. UBYTE interleave = 6;
  55.  
  56. static struct MinList volumelist;
  57.  
  58. static struct IOExtTD *diskchgint_req;
  59. static void diskchginthandler(void)
  60. {
  61.     Signal(ourtask, 1<<diskchgintbit);
  62. }
  63. static struct Interrupt diskchgint =
  64. {
  65.     { NULL, NULL, NT_INTERRUPT, 0, "FS1541" },
  66.     NULL,
  67.     (APTR)&diskchginthandler
  68. };
  69.  
  70. static struct MsgPort *UDStimerport;
  71. struct timerequest *UDStimer;
  72. static int timeropen = 0;
  73.  
  74. static void CreateDollar(struct VolumeNode *node);
  75.  
  76. /*-------------------------------------------------------------------------*/
  77.  
  78. LONG InitVolumeSS(void)
  79. {
  80.     LONG error = 0;
  81.  
  82.     if((UDStimerport = CreateMsgPort()))
  83.     {
  84.         if((UDStimer = CreateIORequest(UDStimerport, sizeof(struct timerequest))))
  85.         {
  86.             if((timeropen = (!OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)UDStimer,0))))
  87.             {
  88.                 if((diskchgintbit = AllocSignal(-1))>=0)
  89.                 {
  90.                     if((diskchgint_req = AllocVec(sizeof(struct IOExtTD), MEMF_PUBLIC)))
  91.                     {
  92.                         NewList((struct List*)&volumelist);
  93.             
  94.                         CopyMem(diskreq, diskchgint_req, sizeof(struct IOExtTD));
  95.                         diskchgint_req->iotd_Req.io_Command = TD_ADDCHANGEINT;
  96.                         diskchgint_req->iotd_Req.io_Data = &diskchgint;
  97.                         diskchgint_req->iotd_Req.io_Length = sizeof(struct Interrupt);
  98.                         diskchgint_req->iotd_Req.io_Flags = 0;
  99.                         SendIO((struct IORequest*)diskchgint_req);
  100.             
  101.                         return(0);
  102.             
  103.                     } else error = ERROR_NO_FREE_STORE;
  104.                 } else error = ERROR_NO_FREE_STORE;
  105.             } else error = ERROR_DEVICE_NOT_MOUNTED;
  106.         } else error = ERROR_NO_FREE_STORE;
  107.     } else error = ERROR_NO_FREE_STORE;
  108.  
  109.     QuitVolumeSS();
  110.     return(error);
  111. }
  112.  
  113. void QuitVolumeSS(void)
  114. {
  115.     if(diskchgint_req)
  116.     {
  117.         diskchgint_req->iotd_Req.io_Command = TD_REMCHANGEINT;
  118.         diskchgint_req->iotd_Req.io_Data = &diskchgint;
  119.         diskchgint_req->iotd_Req.io_Length = sizeof(struct Interrupt);
  120.         diskchgint_req->iotd_Req.io_Flags = 0;
  121.         DoIO((struct IORequest*)diskchgint_req);
  122.  
  123.         FreeVec(diskchgint_req);
  124.     }
  125.  
  126.     if(diskchgintbit >= 0)
  127.         FreeSignal(diskchgintbit);
  128.  
  129.     if(timeropen) {
  130.         StopUDSTimer();
  131.         CloseDevice((struct IORequest*)UDStimer);
  132.     }
  133.  
  134.     if(UDStimer)
  135.         DeleteIORequest(UDStimer);
  136.  
  137.     if(UDStimerport)
  138.         DeleteMsgPort(UDStimerport);
  139. }
  140.  
  141. /*-------------------------------------------------------------------------*/
  142.  
  143. static ULONG bam_secmask[21] = {
  144.     1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
  145.     1<<8,  1<<9,  1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
  146.     1<<0,  1<<1,  1<<2,  1<<3,  1<<4
  147. };
  148.  
  149. static int
  150. CountBits (ULONG l)
  151. {
  152.     BYTE i,n=0;
  153.  
  154.     for (i=0;i<32;i++) {
  155.         if (l&1) n++;
  156.         l=l>>1;
  157.     }
  158.     return (n);
  159. }
  160.  
  161. /* Fix the track allocation info so we can rely on the upper byte without danger */
  162. static void
  163. bam_fix_tracks (struct BAM *b)
  164. {
  165.     int i;
  166.  
  167.     for(i = 0; i < 35; i++) {
  168.         ULONG p = bam->tracks[i];
  169.         int track = i + 1;
  170.         
  171.         if(track<=17)
  172.             p &= 0x00ffff1f;
  173.         else if(track<=24)
  174.             p &= 0x00ffff07;
  175.         else if(track<=30)
  176.             p &= 0x00ffff03;
  177.         else
  178.             p &= 0x00ffff01;
  179.  
  180.         p |= CountBits(p) << 24;
  181.  
  182.         bam->tracks[i] = p;
  183.     }
  184. }
  185.  
  186. void DoDiskInsert(void)
  187. {
  188.     diskreq->iotd_Req.io_Command = TD_CHANGESTATE;
  189.     diskreq->iotd_Req.io_Flags = IOF_QUICK;
  190.     DoIO((struct IORequest*)diskreq);
  191.  
  192.     if(diskreq->iotd_Req.io_Actual)
  193.     {
  194.         /* Switch off the motor. */
  195.         diskreq->iotd_Req.io_Command = TD_MOTOR;
  196.         diskreq->iotd_Req.io_Flags = 0;
  197.         diskreq->iotd_Req.io_Length = 0;
  198.         DoIO((struct IORequest*)diskreq);
  199.     }
  200.     else
  201.     {
  202.         /* Disk has been inserted. */
  203.         int i,t,s;
  204.         UBYTE diskname[20];
  205.         struct VolumeNode *node;
  206.  
  207.         disk_inserted = TRUE;
  208.  
  209.         ResetDisk();
  210.         wprotected = hardwprot;
  211.  
  212.         /* Read Block Allocation Map */
  213.         if(!(bam = (struct BAM*)getblock_ts(18,0)))
  214.             return;
  215.         bam_fix_tracks(bam);
  216.  
  217.         if(bam->id != 'A')
  218.             wprotected = TRUE;
  219.  
  220.         /* Read directory */
  221.         for(i=0, dirsize=0, t=18/*bam->dirt*/, s=1/*bam->dirs*/; /* 1541 always uses 18,1 */
  222.             i<18;
  223.             t=directory[8*i].t, s=directory[8*i].s, i++)
  224.         {
  225.             struct DataBlock *block;
  226.  
  227.             if(!(block = getblock_ts(t, s)))
  228.                 return;
  229.             CopyMem(block, &directory[8*i], 256);
  230.  
  231.             dirsize += 8;
  232.  
  233.             if(!directory[8*i].t)
  234.                 break;
  235.         }
  236.  
  237.         /* Strip trailing type 0x00 entries */
  238.         for(i=dirsize; --i>=0 && directory[i].type == 0x00; dirsize--);
  239.  
  240.         /* Check if this is a volume we know */
  241.         copy64name(diskname, bam->name, 16);
  242.         for(node=(struct VolumeNode*)volumelist.mlh_Head;
  243.             node->node.mln_Succ;
  244.             node=(struct VolumeNode*)(node->node.mln_Succ))
  245.         {
  246.             if(!Stricmp(diskname,&node->name[1]))
  247.             {
  248.                 while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  249.                     DoPackets();
  250.                 curvolumenode = node;
  251.                 curdoslist = node->volnode;
  252.                 curdoslist->dol_Task = ourport;
  253.                 curdoslist->dol_misc.dol_volume.dol_LockList = NULL;
  254.                 UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  255.                 SendEvent(TRUE);
  256.                 return;
  257.             }
  258.         }
  259.  
  260.         /* Create a new volume node */
  261.         if((node = AllocVec(sizeof(struct VolumeNode), MEMF_PUBLIC|MEMF_CLEAR)))
  262.         {
  263.             struct DosList *newvol;
  264.  
  265.             if((newvol = AllocVec(sizeof(struct DosList), MEMF_PUBLIC|MEMF_CLEAR)))
  266.             {
  267.                 /* Generate DosList entry (Volume) */
  268.                 LONG rc;
  269.  
  270.                 newvol->dol_Type = DLT_VOLUME;
  271.                 newvol->dol_Task = ourport;
  272.                 newvol->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK;
  273.                 newvol->dol_Name = (BSTR)MKBADDR(&node->name);
  274.  
  275.                 copy64name(&node->name[1], bam->name, 16);
  276.                 node->name[0] = strlen(&node->name[1]);
  277.  
  278.                 node->volnode = newvol;
  279.                 AddHead((struct List*)&volumelist, (struct Node*)node);
  280.  
  281.                 while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  282.                     DoPackets();
  283.                 rc = AddDosEntry(newvol);
  284.                 UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  285.                 if(rc)
  286.                 {
  287.                     curvolumenode = node;
  288.                     curdoslist = newvol; 
  289.  
  290.                     CreateDollar(node);
  291.  
  292.                     SendEvent(TRUE);
  293.                     MotorOff();
  294.                     return;
  295.                 }
  296.                 FreeVec(newvol);
  297.             }
  298.             FreeVec(node);
  299.         }
  300.     }
  301.  
  302.     MotorOff();
  303. }
  304.  
  305. void DoDiskRemove(void)
  306. {
  307.     disk_inserted = FALSE;
  308.  
  309.     if(curvolumenode)
  310.     {
  311.         if(!curvolumenode->locklist)
  312.         {
  313.             /* No locks -> remove completely */
  314.             while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  315.                 DoPackets();
  316.             RemDosEntry(curdoslist);
  317.             Remove((struct Node*)curvolumenode);
  318.             FreeVec(curvolumenode);
  319.             UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  320.             SendEvent(FALSE);
  321.         }
  322.         else
  323.         {
  324.             /* Do not remove completely, leave disk icon on Workbench. */
  325.             while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  326.                 DoPackets();
  327.             curdoslist->dol_Task = NULL;
  328.             curdoslist->dol_misc.dol_volume.dol_LockList = (BPTR)curvolumenode->locklist;
  329.             UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  330.             SendEvent(FALSE);
  331.         }
  332.  
  333.         curvolumenode = NULL;
  334.         curdoslist = NULL;
  335.     }
  336. }
  337.  
  338. /*-------------------------------------------------------------------------*/
  339.  
  340. static void CreateDollar(struct VolumeNode *node)
  341. {
  342.     UBYTE buf[32], *p=node->dollarbuf;
  343.     int i,j;
  344.     char types[26]="DSPUREERSELQGRLh@@?\\?\\qrhu";
  345.  
  346.     copy64name(buf, bam->name2, 5);
  347.     if(bam->name2[2] == 0xA0)
  348.     {
  349.         buf[2] = ' ';
  350.         copy64name(&buf[3], &bam->name2[3], 2);
  351.     }
  352.  
  353.     sprintf(p, "0 \033[7m\"%-16s\" %-5s\033[0m\n", &node->name[1], buf);
  354.     p += strlen(p);
  355.  
  356.     for(i=0;i<dirsize;i++)
  357.     {
  358.         UBYTE type,typ;
  359.  
  360.         if((type=directory[i].type) == 0x00)
  361.             continue;
  362.  
  363.         copy64name(buf, directory[i].name, 16);
  364.         sprintf(p, "%-5ld\"%s\"", (ULONG)(directory[i].lengthh<<8)|directory[i].lengthl, buf);
  365.         p += strlen(p);
  366.         for(j=0;j<=(16-strlen(buf));j++)
  367.             *p++ = ' ';
  368.         typ=type&15;
  369.         sprintf(p, "%lc%lc%lc%lc\n", types[typ], types[typ+5], types[typ+10], type&0x80 ? (type&0x40 ? '<' : ' ') : '*');
  370.         p += strlen(p);
  371.     }
  372.  
  373.     sprintf(p, "%ld BLOCKS FREE.\n", (LONG)(683-UsedBlocks()));
  374.     p += strlen(p);
  375.  
  376.     node->dollarlen = (ULONG)(p - node->dollarbuf);
  377. }
  378.  
  379. /*-------------------------------------------------------------------------*/
  380.  
  381. static BYTE SearchFreeBlockOnTrack(UBYTE track, UBYTE froms)
  382. {
  383.     UBYTE i,s,numsecs;
  384.     ULONG mask, plan=bam->tracks[track-1];
  385.  
  386.     if(plan>>24 > 0)
  387.     {
  388.         numsecs = SectorsOnTrack(track);
  389.  
  390.         if(track == 18) {
  391.             s = froms + 3;
  392.         } else {
  393.             s = froms + interleave;
  394.         }
  395.  
  396.         for(i=0;i<numsecs;i++,s++)
  397.         {
  398.             s = s % numsecs;
  399.             mask = bam_secmask[s];
  400.  
  401.             if(plan & mask)
  402.             {
  403.                 /* Free sector found. */
  404.                 plan &= ~mask;
  405.                 plan -= (1<<24);
  406.                 bam->tracks[track-1] = plan;
  407.                 return(s);
  408.             }
  409.         }
  410.  
  411.         /* If we reach this point, the BAM is corrupted... */
  412.     }
  413.  
  414.     return(-1);
  415. }
  416.  
  417. UWORD AllocBlock(UBYTE fromt, UBYTE froms)
  418. {
  419.     UBYTE track = fromt;
  420.     BYTE sector;
  421.     BOOL flag = 0;
  422.     BYTE dir = track < 18 ? -1 : 1;
  423.  
  424.     while(1)
  425.     {
  426.         if(track == 18)
  427.             track += dir;
  428.  
  429.         if((sector = SearchFreeBlockOnTrack(track, track==fromt ? froms : 0)) >= 0)
  430.             return((track<<8)|sector);
  431.  
  432.         track += dir;
  433.  
  434.         if(track == 0)
  435.         {
  436.             if(flag)
  437.                 return(0);
  438.             flag++;
  439.             dir = 1;
  440.             track = fromt+1;
  441.         }
  442.  
  443.         if(track == 36)
  444.         {
  445.             if(flag)
  446.                 return(0);
  447.             flag++;
  448.             dir = -1;
  449.             track = fromt-1;
  450.         }
  451.     }
  452. }
  453.  
  454. void FreeBlock(UBYTE t, UBYTE s)
  455. {
  456.     if(t>=1 && t<=35) {
  457.         if(s < SectorsOnTrack(t)) {
  458.             ULONG plan = bam->tracks[t-1];
  459.  
  460.             plan |= bam_secmask[s];
  461.             plan += (1<<24);
  462.             bam->tracks[t-1] = plan;
  463.         }
  464.     }
  465. }
  466.  
  467. UWORD UsedBlocks(void)
  468. {
  469.     int i;
  470.     UWORD r=683;
  471.  
  472.     if(curvolumenode)
  473.     {
  474.         for(i=1;i<=17;i++)
  475.             r -= bam->tracks[i-1]>>24;
  476.         for(i=19;i<=35;i++)
  477.             r -= bam->tracks[i-1]>>24;
  478.     }
  479.  
  480.     return(r);
  481. }
  482.  
  483. /*-------------------------------------------------------------------------*/
  484.  
  485. void OptimizeDirectory(void)
  486. {
  487.     int i, newdirsize=0;
  488.  
  489.     /* Throw out all DEL files */
  490.     for(i=0;i<dirsize;i++)
  491.         if(((directory[i].type) & 0x7) != 0x00)
  492.             memmove(&directory[newdirsize++], &directory[i], sizeof(struct DirEntry));
  493.  
  494.     dirsize = newdirsize;
  495.     memset(&directory[dirsize], 0, (144-newdirsize)*sizeof(struct DirEntry));
  496.  
  497.     /* Clear all Track/Sector fields */
  498.     for(i=0;i<dirsize;i++) {
  499.         directory[i].t = 0;
  500.         directory[i].s = 0;
  501.     }
  502. }
  503.  
  504. /*-------------------------------------------------------------------------*/
  505.  
  506. void StopUDSTimer(void)
  507. {
  508.     if(!CheckIO((struct IORequest*)UDStimer)) {
  509.         AbortIO((struct IORequest*)UDStimer);
  510.         WaitIO((struct IORequest*)UDStimer);
  511.     }
  512.     SetSignal(0, 1<<(UDStimerport->mp_SigBit));
  513. }
  514.  
  515. void StartUDSTimer(void)
  516. {
  517.     StopUDSTimer();
  518.  
  519.     UDStimer->tr_time.tv_secs = 1;
  520.     UDStimer->tr_time.tv_micro = 0;
  521.     UDStimer->tr_node.io_Command = TR_ADDREQUEST;
  522.     SendIO((struct IORequest*)UDStimer);
  523. }
  524.  
  525. void UpdateDiskStructure(void)
  526. {
  527.     int i,n;
  528.     UBYTE s,s2;
  529.  
  530.     if(!CheckIO((struct IORequest*)UDStimer))
  531.         return;
  532.  
  533.     StopUDSTimer();
  534.  
  535.     /* Strip trailing type 0x00 entries */
  536.     for(i=dirsize; --i>=0 && directory[i].type == 0x00; dirsize--);
  537.  
  538.     /* Write BAM and directory blocks */
  539.     bam->dirt = 18;
  540.     bam->dirs = 1;
  541.     bam->tracks[18-1] = 0x11fcff07; /* Block 0 is BAM and Block 1 is first directory block */
  542.     i = dirsize>>3;
  543.     s2 = 1;
  544.     for(n=0;n<=i;n++)
  545.     {
  546.         s = s2;
  547.  
  548.         if(n<i)
  549.         {
  550.             s2 = SearchFreeBlockOnTrack(18,s); /* will always succeed */
  551.             directory[n<<3].t = 18;
  552.             directory[n<<3].s = s2;
  553.         }
  554.         else
  555.         {
  556.             directory[n<<3].t = 0;
  557.             directory[n<<3].s = 0xff;
  558.         }
  559.  
  560.         putblock_ts(18,s,&directory[n<<3]);
  561.     }
  562.     putblock_ts(18,0,bam);
  563.     MotorOff();
  564.  
  565.     CreateDollar(curvolumenode);
  566. }
  567.  
  568. /*-------------------------------------------------------------------------*/
  569.  
  570. BPTR makelock(LONG flkey, LONG axs)
  571. {
  572.     struct FileLock *fl;
  573.  
  574.     if((fl = AllocVec(sizeof(struct FileLock), MEMF_PUBLIC|MEMF_CLEAR)))
  575.     {
  576.         fl->fl_Key = flkey;
  577.         fl->fl_Access = axs;
  578.         fl->fl_Task = ourport;
  579.         fl->fl_Volume = MKBADDR(curdoslist);
  580.         fl->fl_Link = (BPTR)curvolumenode->locklist;
  581.         curvolumenode->locklist = fl;
  582.     }
  583.  
  584.     return(MKBADDR(fl));
  585. }
  586.  
  587. void freelock(struct FileLock *fl)
  588. {
  589.     struct VolumeNode *node;
  590.  
  591.     for(node=(struct VolumeNode*)volumelist.mlh_Head;
  592.         node->node.mln_Succ;
  593.         node=(struct VolumeNode*)(node->node.mln_Succ))
  594.     {
  595.         struct FileLock *cur,*last;
  596.  
  597.         for(cur=node->locklist, last=(struct FileLock*)&node->locklist;
  598.             cur;
  599.             last=cur, cur=(struct FileLock*)last->fl_Link)
  600.         {
  601.             if(cur == fl)
  602.             {
  603.                 last->fl_Link = cur->fl_Link;
  604.                 fl->fl_Task = NULL;
  605.                 FreeVec(fl);
  606.  
  607.                 if(!node->locklist && !node->volnode->dol_Task)
  608.                 {
  609.                     /* An unmounted volume does not have any locks open
  610.                        any more, so we can safely remove the volume node. */
  611.  
  612.                     while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  613.                         DoPackets();
  614.                     RemDosEntry((struct DosList*)node->volnode);
  615.                     Remove((struct Node*)node);
  616.                     FreeVec(node);
  617.                     UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  618.                     SendEvent(FALSE);
  619.                 }
  620.  
  621.                 return;
  622.             }
  623.         }
  624.     }
  625. }
  626.  
  627. /* Is an object still lockable with the respective access mode? */
  628. BOOL lockable(UBYTE t, UBYTE s, LONG mode)
  629. {
  630.     struct FileLock *fl;
  631.     LONG searchkey = t<<8|s;
  632.  
  633.     for(fl=curvolumenode->locklist; fl; fl=(struct FileLock*)fl->fl_Link)
  634.     {
  635.         if(fl->fl_Key == searchkey)
  636.         {
  637.             if(mode == EXCLUSIVE_LOCK)
  638.                 return(FALSE);
  639.             else
  640.             {
  641.                 if(fl->fl_Access == EXCLUSIVE_LOCK)
  642.                     return(FALSE);
  643.             }
  644.         }
  645.     }
  646.  
  647.     return(TRUE);
  648. }
  649.  
  650. /*
  651.   Local Variables:
  652.   mode:c
  653.   c-basic-offset:8
  654.   End:
  655. */
  656.